﻿using QuickLogin.Properties;
using QuickLogin.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace QuickLogin.Connect
{
    public static class WebServiceComm
    {
        /// <summary>
        /// 验证服务地址
        /// </summary>
        //public static string AuthServerUrl { get; set; } = "https://gls.ddo.com/GLS.AuthServer/Service.asmx";
        public static string AuthServerUrl { get; set; } = "https://gls-auth.ddo.com/GLS.AuthServer/Service.asmx";
        /// <summary>
        /// 登陆排队服务器
        /// </summary>
        public static string LoginQueueUrl { get; set; } = "https://gls.ddo.com/GLS.AuthServer/LoginQueue.aspx";
        /// <summary>
        /// 排队参数
        /// </summary>
        public static string LoginQueueTakeANumberParameters { get; set; }
        /// <summary>
        /// 登陆参数
        /// </summary>
        public static string ArgTemplate { get; set; }
        /// <summary>
        /// GlsTicket存活时长
        /// </summary>
        public static string GlsTicketLifeTime { get; set; } = "21600";
        /// <summary>
        /// 新闻地址
        /// </summary>
        public static string NewsFeedUrl { get; set; } = "https://forums-old.ddo.com/en/launcher-feed.xml";
        /// <summary>
        /// 2023.05.15更新
        /// 服务描述配置
        /// </summary>
        const string DNDLAUNCHER_SERVER_CONFIG_URL = "http://gls.ddo.com/launcher/ddo/dndlauncher.server.config.xml";

        /// <summary>
        /// 数据中心地址，获得服务器地址，状态等数据
        /// </summary>
        const string DATA_CENTER_SERVER = "http://gls.ddo.com/GLS.DataCenterServer/Service.asmx";

        public static Dictionary<string, string> GetServerConfig()
        {
            XDocument xml = XDocument.Load(DNDLAUNCHER_SERVER_CONFIG_URL);
            var serCfg = (
                from item in xml.Descendants("add")
                select new KeyValuePair<string, string>(item.Attribute("key").Value, item.Attribute("value").Value)
                     ).ToDictionary(k => k.Key, v => v.Value);
            //验证地址
            if (serCfg.TryGetValue("GameClient.Arg.authserverurl", out string authUrl))
            {
                AuthServerUrl = authUrl;
            }
            //排队地址
            if (serCfg.TryGetValue("WorldQueue.LoginQueue.URL", out string loginQueue))
            {
                LoginQueueUrl = loginQueue;
            }
            //排队参数
            if (serCfg.TryGetValue("WorldQueue.TakeANumber.Parameters", out string takeANumber))
            {
                LoginQueueTakeANumberParameters = takeANumber;
            }
            //登陆参数
            if (serCfg.TryGetValue("GameClient.WIN32.ArgTemplate", out string argTemplate))
            {
                ArgTemplate = argTemplate;
            }
            //Ticket有效期
            if (serCfg.TryGetValue("GameClient.Arg.glsticketlifetime", out string glsticketlifetime))
            {
                GlsTicketLifeTime = glsticketlifetime;
            }
            //新闻
            if (serCfg.TryGetValue(" URL.NewsFeed", out string newsFeed))
            {
                NewsFeedUrl = newsFeed;
            }
            return serCfg;
        }

        /// <summary>
        /// 获得服务器列表
        /// </summary>
        /// <returns></returns>
        public static Datacenter GetDatacenter()
        {
            string xml = Resources.GetDatacenters;
            var xDoc = CallUrlBySoap(DATA_CENTER_SERVER, xml);
            //var xDoc = XDocument.Parse(Resources.GetDatacenters_feedback); //测试
            Datacenter datacenter = new Datacenter();
            var xWorlds = xDoc.Descendants(XmlHelper.xNamespace + "World");
            datacenter.Worlds = (from item in xWorlds
                                 select new World()
                                 {
                                     Name = item.GetValByNamespace("Name"),
                                     ChatServerUrl = GetRandomServerUrl(item.GetValByNamespace("ChatServerUrl")),
                                     //直接访问这个地址可以取得服务器的状态
                                     //http://gls.ddo.com/GLS.DataCenterServer/StatusServer.aspx?s=10.192.145.17
                                     StatusServerUrl = item.GetValByNamespace("StatusServerUrl"),
                                     Language = item.GetValByNamespace("Language"),
                                     Order = item.GetValByNamespace("Order")
                                 }
                     ).ToList();
            var xDatacenter = xDoc.Descendants(XmlHelper.xNamespace + "Datacenter").FirstOrDefault();
            //登录服务器
            //https://gls-auth.ddo.com/GLS.AuthServer/Service.asmx
            datacenter.AuthServer = xDatacenter.GetValByNamespace("AuthServer");
            datacenter.LauncherConfigurationServer = xDatacenter.GetValByNamespace("LauncherConfigurationServer");
            datacenter.PatchServer = xDatacenter.GetValByNamespace("PatchServer");
            return datacenter;
        }
        /// <summary>
        /// 获取服务器状态信息
        /// </summary>
        /// <param name="StatusServerUrl"></param>
        /// <returns></returns>
        public static ServerStatus GetServerStatus(string WorldStatusServerUrl)
        {
            var xDoc = XmlHelper.CallUrl(WorldStatusServerUrl);
            return new ServerStatus(xDoc);
        }

        /// <summary>
        /// 验证用户名密码
        /// </summary>
        /// <param name="AuthServer"></param>
        /// <param name="UserName"></param>
        /// <param name="Password"></param>
        /// <returns></returns>
        public static UserProfile LoginAccount(string UserName, string Password)
        {
            string xml = Resources.LoginAccount;
            var xDoc = CallUrlBySoap(AuthServerUrl, string.Format(xml, UserName, Password), "gls-auth.ddo.com");
            //var xDoc = XDocument.Parse(Resources.LoginAccount_feedback); //测试 
            UserProfile userProfile = new UserProfile();
            var xSubscription = xDoc.Descendants(XmlHelper.xNamespace + "GameSubscription");
            userProfile.SubscriptionUser = (from item in xSubscription
                                            where item.Element(XmlHelper.xNamespace + "Game").Value == "DDO"
                                            select new SubscriptionUser()
                                            {
                                                SubscriptionName = item.GetValByNamespace("Name"),
                                                Description = item.GetValByNamespace("Description"),
                                                Status = item.GetValByNamespace("Status"),
                                                ProductTokens = GetProductTokens(item)
                                            }
                     ).ToList();
            userProfile.Ticket = xDoc.Descendants(XmlHelper.xNamespace + "LoginAccountResult").FirstOrDefault().Element(XmlHelper.xNamespace + "Ticket").Value;
            return userProfile;
        }
        public static List<string> GetProductTokens(XElement item)
        {
            try
            {
                if (item != null)
                {
                    var node = item.Element(XmlHelper.xNamespace + "ProductTokens");
                    if (node != null)
                    {
                        var els = node.Elements();
                        if (els != null && els.Count() > 0)
                        {
                            var list = (from x in els select x.Value);
                            if (list != null && list.Count() > 0)
                            {
                                return list.ToList();
                            }
                        }
                    }
                }
            }
            catch (Exception e) { Trace.WriteLine(e.ToString()); }
            return null;
        }

        public static TakeNumber TakeANumber(string SubscriptionName, string Ticket, string QueueURL)
        {
            string postData = string.Format(
                LoginQueueTakeANumberParameters,
                Comm.UrlEncode(SubscriptionName, Encoding.ASCII),
                Comm.UrlEncode(Ticket, Encoding.ASCII),
                Comm.UrlEncode(QueueURL, Encoding.ASCII));
            //请求信息
            var xDoc = XmlHelper.CallUrl(LoginQueueUrl, RequestMethod.POST, "application/x-www-form-urlencoded", postData);
            //登录队列， 人多时有排队现象， 不做控制会登录不了，2019-07-08
            return new TakeNumber(xDoc);
        }



        public static T GetRandom<T>(this T[] array)
        {
            var index = new Random(DateTime.Now.Millisecond).Next(array.Length);
            return array[index];
        }
        public static int GetRandomIndex<T>(this T[] array)
        {
            var index = new Random(DateTime.Now.Millisecond).Next(array.Length);
            return index;
        }
        public static string GetRandomServerUrl(string Url)
        {
            if (Url.Contains(';'))
            {
                return Url.Trim(';').Split(';').GetRandom();
            }
            else return Url;
        }
        /// <summary>
        /// 调用WebService，SOAP 1.2协议
        /// </summary>
        /// <param name="Uri"></param>
        /// <param name="xml"></param>
        /// <returns></returns>
        static XDocument CallUrlBySoap(string Uri, string RequestBody, string host = "gls.ddo.com") =>
            XmlHelper.CallUrl(Uri, RequestMethod.POST, "application/soap+xml;charset=utf-8", RequestBody, HeaderConfig: hc => hc.SetHeaderValue("Host", host));
    }
    public class Datacenter
    {
        public List<World> Worlds;
        public string AuthServer;
        public string PatchServer;
        public string LauncherConfigurationServer;
    }
    public class World
    {
        public string Name;
        public string ChatServerUrl;
        public string StatusServerUrl;
        public string Order;
        public string Language;
        public override string ToString()
        {
            return Name;
        }
    }


    public class UserProfile
    {
        public string Ticket;
        public SubscriptionUser SelectUser;
        public List<SubscriptionUser> SubscriptionUser;
    }
    public class SubscriptionUser
    {
        public string SubscriptionName;
        public string Status;
        public string Description;
        public List<string> ProductTokens;
    }

    public class ServerStatus
    {
        /*
         <Status>
  <logintiers>0;1;2;</logintiers>
  <name>Cannith</name>
  <queuenames>B2BC2C51-E34A-44B6-B440-7B3B8708BE02;2E9F9260-623A-4B45-90CC-B503B871B2DF;</queuenames>
  <allow_billing_role>TurbineEmployee,TurbineVIP,StormreachLimited,StormreachStandard,StormreachGuest,StormreachEUPre</allow_billing_role>
  <lastassignedqueuenumber>0x00011D22</lastassignedqueuenumber>
  <logintierlastnumbers>72992;72994;72991;</logintierlastnumbers>
  <farmid>25</farmid>
  <deny_admin_role/>
  <world_full>false</world_full>
  <wait_hint>34.030</wait_hint>
  <queueurls>http://10.192.145.17:7082/LoginQueue;http://10.192.145.17:7081/LoginQueue;</queueurls>
  <allow_admin_role>Server,CustomerService,Observer,SeniorCustomerService,LeadCustomerService,Test</allow_admin_role>
  <nowservingqueuenumber>0x00011D22</nowservingqueuenumber>
  <deny_billing_role/>
  <logintiermultipliers>1;2;3;</logintiermultipliers>
  <loginservers>198.252.160.41:9004;198.252.160.41:9003;</loginservers>
  <world_pvppermission>0</world_pvppermission>
</Status>
             
             */
        public ServerStatus(XDocument xml)
        {
            XElement xDocument = xml.Root;
            var LoginServers = xDocument.GetVal("loginservers").TrimEnd(';').Split(';');
            var QueueURLs = xDocument.GetVal("queueurls").TrimEnd(';').Split(';');
            IsFull = xDocument.GetVal("world_full") == "true";
            //随机获取一个登陆地址与排队地址
            if (QueueURLs.Length == LoginServers.Length)
            {
                var index = QueueURLs.GetRandomIndex();
                QueueURL = QueueURLs[index];
                LoginServer = LoginServers[index];
            }
            else
            {
                LoginServer = LoginServers.GetRandom();
                QueueURL = QueueURLs.GetRandom();
            }
        }
        public bool IsFull;
        public string QueueURL;
        public string LoginServer;
    }
    public class TakeNumber
    {
        /*
    <Result>
    <Command>TakeANumber</Command>
    <HResult>0x00000000</HResult>
    <QueueName>7EC32C5C-894A-40C6-B7E2-C0402DD8B695</QueueName>
    <QueueNumber>0x000018c7</QueueNumber>
    <NowServingNumber>0x000018cd</NowServingNumber>
    <LoginTier>1</LoginTier>
    <ContextNumber>0x000007b0</ContextNumber>
    </Result>
    */
        public TakeNumber(XDocument xml)
        {
            XElement xDocument = xml.Root;
            QueueName = xDocument.GetVal("QueueName");
            string qNum = xDocument.GetVal("QueueNumber").ToUpper().TrimStart('0', 'X');
            string nowNun = xDocument.GetVal("NowServingNumber").ToUpper().TrimStart('0', 'X');
            string cNum = xDocument.GetVal("ContextNumber").ToUpper().TrimStart('0', 'X');
            string tier = xDocument.GetVal("LoginTier");
            if (!string.IsNullOrEmpty(qNum.Trim()))
            {
                QueueNumber = Convert.ToInt32(qNum, 16);
            }
            if (!string.IsNullOrEmpty(nowNun.Trim()))
            {
                NowServingNumber = Convert.ToInt32(nowNun, 16);
            }
            if (!string.IsNullOrEmpty(cNum.Trim()))
            {
                ContextNumber = Convert.ToInt32(cNum, 16);
            }
            if (!string.IsNullOrEmpty(tier.Trim()))
            {
                LoginTier = Convert.ToInt32(tier, 10);
            }
        }
        public string QueueName;
        public int QueueNumber;
        public int NowServingNumber;
        public int ContextNumber;
        public int LoginTier;
    }

}

/*


http://gls.ddo.com/launcher/ddo/dndlauncher.server.config.xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="LauncherConfig.DateTime" value="10/20/10 6:40 AM"/>
    <add key="LauncherConfig.RefreshFrequency" value="15"/> <!-- minutes -->

    <add key="GameName" value="DDO"/>
    <add key="Patching.ProductCode" value="DDO"/>


    <!-- CLIENT LAUNCHING -->
    <add key="GameClient.WIN32.Filename" value="dndclient.exe"/>
	<add key="GameClient.WIN64.Filename" value="dndclient64.exe" />
    <add key="GameClient.WIN32.ArgTemplate" value="-a {SUBSCRIPTION} -h {LOGIN} --glsticketdirect {GLS} --chatserver {CHAT} --rodat on --language {LANG} --gametype DDO --authserverurl {AUTHSERVERURL} --glsticketlifetime {GLSTICKETLIFETIME}"/>
	
	<add key="GameClient.WIN32Legacy.Filename" value="dndclient_awesomium.exe" />

    

    <add key="EnableStayLoggedInFeature" value="False" />


	
    <add key="GameClient.OSX.Filename" value="dndclient.app"/>
    <add key="GameClient.OSX.ArgTemplate" value="-a {SUBSCRIPTION} -h {LOGIN} --glsticketdirect {GLS} --chatserver {CHAT} --rodat on --language {LANG} --gametype DDO --authserverurl {AUTHSERVERURL} --glsticketlifetime {GLSTICKETLIFETIME} --supporturl {SUPPORTURL} --bugurl {BUGURL} --supportserviceurl {SUPPORTSERVICEURL}"/>

    <add key="GameClient.Arg.crashreceiver" value="http://crash.ddo.com:8080/CrashReceiver-1.0"/>
    <add key="GameClient.Arg.authserverurl" value="https://gls.ddo.com/GLS.AuthServer/Service.asmx"/>
    <add key="GameClient.Arg.glsticketlifetime" value="21600"/>
    <!-- CLIENT LAUNCHING -->	

    <add key="GameClient.ResetGraphicsArg" value=" --safe"/>

    <add key="GameClient.AlwaysPatchHighRes" value="true"/>
    <!-- Standalone Updater -->
    <add key="GameClient.RequiredVersion" value="0"/>
    <add key="GameClient.ForwardVersion" value="0"/>
    <add key="URL.UpdateDownload" value="http://downloads.turbine.com" />
    <add key="Patch.UpdaterNameFormat" value="{0}updater_{1}_{2}.exe" />

    <add key="DataCenterBrowser.BatchWorldStatus" value="true"/>


    <add key="URL.Support" value="https://help.standingstonegames.com"/>
    <add key="URL.Home" value="http://www.ddo.com"/>
    <add key="URL.Community" value="https://forums.ddo.com/forums/"/>
    <add key="URL.Account" value="https://myaccount.standingstonegames.com/?billing[target_lang]={lang}"/>
    <add key="URL.NewAccount" value="https://signup.ddo.com/ddo.php"/>
    <add key="URL.ForgotPassword" value="https://myaccount.standingstonegames.com/?page_id=29&amp;billing[process]=13"/>

    <add key="URL.BannerSource.Steam" value="http://live.ddo.com/sites/ddolauncher/steam/{lang}/ddo_launcherad.png?x=0&amp;y=78" />
    <add key="URL.NewAccount.Steam" value="http://live.ddo.com/sites/launcher/ddo/redirects/NewAccountSteam.php?lang={lang}" />
	<add key="URL.PermaDeathServerInfo" value="https://www.ddo.com/news/ddo-hardcore-league"/>

    <add key="URL.Account.Post" value="https://myaccount.standingstonegames.com/?page_id=29&amp;billing[target_lang]={lang}"/>
    <add key="Format.Account.Login" value=""/>
    <add key="Format.Account.BuyNow" value="form_user_name={0}&amp;form_user_pass={1}&amp;siteuser[action]=login&amp;billing[process]=17&amp;billing[forms][subscriptionName]={2}&amp;billing[scenario]=DDO_BUY_NOW_POPUP&amp;billing[forms][productCode]=DDO&amp;billing[forms][purchaseProductCode]=DDOBuy&amp;billing[forms][purchasePlanCode]=DDO-F2PUp" />
    <add key="Activate.Account.BuyNow" value="false"/>
    <add key="Activate.Account.VIPDisplay" value="true"/>
    <add key="Threshold.Account.DaysLeft" value="15"/>
    <add key="Activate.Account.DaysLeft" value="true"/>
    <add key="LauncherConfig.SubscriptionRefreshFrequency" value="60"/>
    <add key="Subscription.FreeToPlay" value="true"/>

    <add key="URL.PrivacyPolicy" value="http://www.turbine.com/?page_id=59"/>

    <add key="URL.NewsFeed" value="https://forums-old.ddo.com/en/launcher-feed.xml"/>
    <add key="Launcher.NewsFeedCSSUrl" value="http://live.ddo.com/sites/launcher/ddo/newsfeed.css"/>
    <add key="URL.NewsStyleSheet" value="http://live.ddo.com/sites/launcher/ddo/newsstylesheet.xslt"/>
    <add key="URL.AlertsStyleSheet" value="http://live.ddo.com/sites/launcher/ddo/alertsstylesheet.xslt"/>
    <add key="URL.NewsFeed.Timeout" value="10" />

    <add key="URL.LogoButton1" value="http://www.turbine.com"/>
    <add key="URL.LogoButton2" value="http://www.wizards.com"/>
    <add key="URL.LogoButton3" value="http://www.hasbro.com"/>
    <add key="URL.LogoButton4" value="http://www.atari.com"/>

    <add key="WorldUpdateRate" value="1"/>	            <!-- minutes -->

    <add key="PatchWindow" value="30"/>	                <!-- minutes -->
    <add key="PatchConnectRetryInterval" value="1"/>	<!-- minutes -->
    <add key="DisablePatch" value="false"/>

    <add key="EmailAddress.Errors" value="LauncherErrors@turbine.com"/>

    <add key="Eula.en.FilePath" value="en\DDO Eula.rtf"/>

    <add key="Legal.en.Titles" value="End User License Agreement|Terms of Service"/>
    <add key="Legal.DE.Titles" value="Endnutzer-Lizenzvereinbarung|Nutzungsbedingungen"/>
    <add key="Legal.FR.Titles" value="Contrat de License Utilisateur Final|Conditions de Service"/>
    <add key="Legal.English.Titles" value="End User License Agreement|Terms of Service"/>
    <add key="Legal.en-GB.Titles" value="End User License Agreement|Terms of Service"/>

    <add key="Legal.en.FilePaths" value="en\DDO EULA.rtf|en\DDO TOS.rtf"/>
    <add key="Legal.DE.FilePaths" value="DE\DDO EULA.rtf|DE\DDO TOS.rtf"/>
    <add key="Legal.FR.FilePaths" value="FR\DDO EULA.rtf|FR\DDO TOS.rtf"/>
    <add key="Legal.English.FilePaths" value="en\DDO EULA.rtf|en\DDO TOS.rtf"/>
    <add key="Legal.en-GB.FilePaths" value="en\DDO EULA.rtf|en\DDO TOS.rtf"/>

    <add key="URL.DownloadFilesList" value="http://akamai.ddo.com/ddo/patch/splashscreen/DownloadFilesList.xml"/>
    <add key="URL.ReqSoftwareInstall" value="http://akamai.ddo.com/ddo/PreReqProd/PreInstallListDDOProd.xml"/>


    <add key="URL.BannerSource" value="http://live.ddo.com/sites/ddolauncher/{lang}/ddo_launcherad.png?x=1&amp;y=77"/>
    <add key="URL.BannerTarget" value="http://live.ddo.com/sites/launcher/ddo/redirects/BannerTarget.php?lang={lang}"/> 
    <!-- Login Queue -->
    <add key="WorldQueue.LoginQueue.URL" value="https://gls.ddo.com/GLS.AuthServer/LoginQueue.aspx"/> 
    <add key="WorldQueue.TakeANumber.Parameters" value="command=TakeANumber&amp;subscription={0}&amp;ticket={1}&amp;ticket_type=GLS&amp;queue_url={2}"/>    
    <add key="WorldQueue.LeaveQueue.Parameters" value="command=LeaveQueue&amp;subscription={0}&amp;context={1}&amp;ticket_type=GLS&amp;queue_url={2}"/> 
    <add key="WorldQueue.Threshold.WaitTimeMultiplier" value="1.00" />
    <add key="WorldQueue.Threshold.Medium" value="300" />
    <add key="WorldQueue.Threshold.Long" value="900" />
    <add key="WorldQueue.PollTimer" value ="120" />	

    <!-- ENABLE TRANSFER -->
    <add key="ShardTransfer.Enabled" value="true" />
    <add key="ShardTransfer.ServiceURL" value="http://xfer.ddo.com/TurbineTransferService/TurbineTransferService.svc" />
    <add key="ShardTransfer.StoreURL" value="http://d12.parature.com/ics/support/kbanswer.asp?deptID=24047&amp;task=knowledge&amp;questionID=6781" />	
    <!-- END ENABLE TRANSFER -->
	
    <!-- Akamai Download Information -->		
    <add key="URL.AkamaiDownloadURL" value="http://installer.ddo.com/dnd/"/>
    <add key="Game.Version" value="5000.0050.3264.4021"/>

  </appSettings>
</configuration>

 */